package samples.tut2;

import java.util.ArrayList;
import java.util.List;

import org.creavi.engine.quickstart.QuickStartGame;

import com.jme.bounding.BoundingSphere;
import com.jme.input.KeyInput;
import com.jme.math.Vector3f;
import com.jme.scene.shape.Box;
import com.jme.scene.shape.Sphere;

/**
 * Este es un ejemplo de un "Space Invaders".
 * 
 * Manejas tu nave con las flechitas Izquierda y derecha y disparas con la barra
 * espaciadora.
 * 
 * El juego aun no tiene criterio para terminar ni muestra algun menu.
 * 
 * Lo unico que hace es bajar a los enemigos, y te deja disparar para ir
 * eliminandolos.
 * 
 * @author Hilario
 */
public class Tutorial2 extends QuickStartGame {

	public static void main(String[] args) {
		new Tutorial2().start();
	}

	/**
	 * Esta variable almacena a todos los enemigos en un arreglo
	 */
	Box[][] enemigos;

	/**
	 * Este listado guarda las balas que el usuario esta disparando
	 */
	List<Sphere> balas;

	/**
	 * Esta variable guarda a la nave para que la controles con las flechitas
	 */
	Box nave;

	@Override
	protected void initializeGame() {
		Vector3f c1 = new Vector3f(-.3f, -.3f, -.3f);
		Vector3f c2 = new Vector3f(.3f, .3f, .3f);

		// Primero crearemos a 200 enemigos
		enemigos = new Box[10][];
		for (int row = 0; row < 10; row++) {
			enemigos[row] = new Box[20];
			for (int col = 0; col < 20; col++) {

				// Creamos a un enemigo
				enemigos[row][col] = new Box("enemigo_" + row + "_" + col, c1,
						c2);

				// A cada enemigo le damos una posicion independiente
				enemigos[row][col].setLocalTranslation(10 - col, 2 + row, 0);

				// Le ponemos un "BoundingVolume" para poder realizar colisiones
				enemigos[row][col].setModelBound(new BoundingSphere());
				// Le decimos a jMonkeyEngine que hicimos un cambio en el
				// Bounding Box, y que actualice la informacion relacionada
				enemigos[row][col].updateModelBound();

				// Agregamos al enemigo a la escena
				rootNode.attachChild(enemigos[row][col]);
			}
		}

		// Ahora creamos a la nave
		nave = new Box("nave", c1, c2);

		// La ponemos en la parte inferior de la pantalla
		nave.setLocalTranslation(0, -10, 0);

		// Y la agregamos a la escena
		rootNode.attachChild(nave);

		// Creamos un listado de Esferas
		balas = new ArrayList<Sphere>();
	}

	/**
	 * Esta variable sirve para ver en que direccion se mueven los enemigos
	 * 
	 * Estado de la animacion: 0 = Derecha 1 = Abajo (por la derecha) 2 =
	 * Izquierda 3 = Abajo (por la izquierda)
	 */
	int estado = 0;

	/**
	 * Unidades que se tienen que mover los enemigos
	 */
	float cantidad = 5;

	/**
	 * Velocidad a la que se mueven los enemigos
	 */
	float velocidad = 1f;

	/**
	 * En este metodo se realizaran las siguientes acciones:
	 * 
	 * 1. Mover la navesita con las flechitas 2. Disparar 3. Mover a los
	 * enemigos 4. Actualizar el estado del movimiento de los enemigos 5.
	 * Revisar colisiones y eliminar balas y enemigos que choquen
	 */
	@Override
	protected void updateGame(float time) {
		// Mover a la navesita
		if (keyboard.isKeyDown(KeyInput.KEY_LEFT)) {
			// Movemos la navecita hacia la izquierda
			nave.getLocalTranslation().addLocal(-10 * time, 0, 0);

			// No se puede mover a mas de 15 unidades del centro
			if (nave.getLocalTranslation().x < -15) {
				nave.getLocalTranslation().setX(-15);
			}
		}
		if (keyboard.isKeyDown(KeyInput.KEY_RIGHT)) {
			// Movemos la navecita hacia la derecha
			nave.getLocalTranslation().addLocal(10 * time, 0, 0);

			// No se puede mover a mas de 15 unidades del centro
			if (nave.getLocalTranslation().x > 15) {
				nave.getLocalTranslation().setX(15);
			}
		}

		// Disparar
		if (isKeyPressed(KeyInput.KEY_SPACE)) {
			disparar();
		}

		// Animar Enemigos
		float mov = velocidad * time;
		if (mov > cantidad) {
			mov = cantidad;
			cantidad = 0;
		} else {
			cantidad -= mov;
		}
		for (int row = 0; row < 10; row++) {
			for (int col = 0; col < 20; col++) {
				if (enemigos[row][col] != null) {
					if (estado == 0) {
						// En el estado 0 movemos a los enemigos a la derecha
						enemigos[row][col].getLocalTranslation().addLocal(mov,
								0, 0);
					} else if (estado == 1 || estado == 3) {
						// En el estado 1 y 3 movemos a los enemigos hacia abajo
						enemigos[row][col].getLocalTranslation().addLocal(0,
								-mov, 0);
					} else if (estado == 2) {
						// En el estado 2 movemos a los enemigos a la izquierda
						enemigos[row][col].getLocalTranslation().addLocal(-mov,
								0, 0);
					}
				}
			}
		}

		// Cambiar de estado a los enemigos
		if (cantidad == 0) {
			if (estado == 0) {
				cantidad = 1;
				estado = 1;
			} else if (estado == 1) {
				cantidad = 10;
				estado = 2;
			} else if (estado == 2) {
				cantidad = 1;
				estado = 3;
			} else if (estado == 3) {
				cantidad = 10;
				estado = 0;
			}
		}

		// Animar balitas y checar colisiones
		for (int idx = balas.size() - 1; idx >= 0; idx--) {
			Sphere bala = balas.get(idx);
			bala.getLocalTranslation().addLocal(0, 20 * time, 0);
			if (bala.getLocalTranslation().y > 12) {
				// Borramos a la bala si se pasa de largo
				rootNode.detachChild(bala);
				balas.remove(idx);
			} else {
				boolean continuar = true;
				// Checamos la bala contra todos los enemigos
				for (int row = 0; row < 10 && continuar; row++) {
					for (int col = 0; col < 20 && continuar; col++) {
						if (enemigos[row][col] != null) {
							// Si el enemigo aun sigue vivo
							if (bala.hasCollision(enemigos[row][col], true)) {
								// Si la bala choca con el enemigo

								// Borramos al enemigo
								rootNode.detachChild(enemigos[row][col]);
								enemigos[row][col] = null;

								// Borramos a la bala
								rootNode.detachChild(bala);
								balas.remove(idx);

								// Terminamos la busqueda
								continuar = false;

								// Incrementamos la velocidad
								velocidad += .03f;
							}
						}
					}
				}
			}
		}

	}

	/**
	 * Este metodo crea nuevas balas
	 */
	private void disparar() {
		// Se crea una bala en forma de Esfera
		Sphere bala = new Sphere("balita_X", 3, 3, .3f);
		// Ponemos la bala en la misma posicion que la nave
		bala.setLocalTranslation(nave.getLocalTranslation().clone());
		// Le asignamos una esfera como Bounding Box
		bala.setModelBound(new BoundingSphere());
		// Actualizamos la informacion de Bounding de la bala
		bala.updateModelBound();
		// Agregamos a la bala al listado (para que pueda ser movida despues)
		balas.add(bala);

		// Agregamos a la bala a la escena
		rootNode.attachChild(bala);
	}

}
